using Godot;
using System;
using System.Collections.Generic;
using Smr.枚举;
using Smr.基类;
using Smr.索引;
using Smr;
using System.Threading.Tasks;

public partial class 战斗场景 : Node2D
{
	[Signal] public delegate void 信号战斗结束EventHandler(Godot.Collections.Array<int> 掉落道具);
	[Export] private PackedScene 角色场景;
	[Export] private Node2D 角色站位节点;
	[Export] private Node2D 角色放置层;
	[Export] private Label 回合数标签;
	[Export] private Label 地图名标签;
	[Export] private Timer 遇敌间隔;
	[Export] private 组件遇敌文本 遇敌文本显示;

	private Godot.Collections.Array<Node> 站位数组;
	private bool 战斗开始 = false;

	public override void _EnterTree()
	{
		游戏管理.置组件实例("战斗场景", this);
	}

	public override void _Ready()
	{
		站位数组 = 角色站位节点.GetChildren();
		遇敌文本显示.文本标签.Text = $"搜索{游戏存档.当前地图}中";
		战斗回合();
	}

	private async void 战斗回合()
	{
		do
		{
			清空角色();
			回合数标签.Visible = false;
			地图名标签.Visible = false;
			遇敌文本显示.Visible = true;
			遇敌间隔.Start(方法.取随机数.Next(配置.随机遇敌间隔[0], 配置.随机遇敌间隔[1]));
			await ToSignal(遇敌间隔, Timer.SignalName.Timeout);
			遇敌文本显示.Visible = false;

			List<组件角色> 角色组 = [];
			List<E道具索引> 掉落道具组 = [];
			int 掉落经验 = 0;

			// 生成玩家实例
			int 玩家站位 = (int)E角色战斗站位.本后中;
			角色组.Add(注册角色(玩家站位, (Marker2D)站位数组[玩家站位], 游戏存档.玩家.取综合属性(游戏管理.装备栏实例.取装备栏战斗属性())));

			// 初始化宠物站位
			int 宠物站位 = (int)E角色战斗站位.本前中;
			// 生成宠物
			for (int i = 0; i < 游戏存档.宠物.Count; i++)
			{
				// 判断宠物是否参战
				if (游戏存档.宠物[i].是否参战)
				{
					角色组.Add(注册角色(宠物站位, (Marker2D)站位数组[宠物站位], 游戏存档.宠物[i].取综合属性(游戏管理.装备栏实例.取装备栏战斗属性())));
					宠物站位 += 1;
				}
			}

			// 生成敌人实例
			int 敌人总数 = 方法.取随机数.Next(1, 7); // 随机敌人数
			var 地图数据 = 地图模型.取模型(游戏存档.当前地图); // 获取地图配置数据
			if (地图数据 == null) // 判断地图是否获取成功
			{
				游戏管理.日志实例.置失败文本("地图数据获取失败！");
				return;
			}
			IReadOnlyList<E敌人索引> 敌人配置 = 地图数据.敌人; // 获取敌人名称
			for (int i = 0; i < 敌人总数; i++) // 生成敌人
			{
				E敌人索引 敌人名称 = 敌人配置[方法.取随机数.Next(0, 敌人配置.Count)];
				int 敌人站位 = (int)E角色战斗站位.敌后中 + i;
				C敌人模型 敌人角色模型 = 敌人模型.取模型(敌人名称);
				if (敌人角色模型 == null) // 判断地图是否获取成功
				{
					游戏管理.日志实例.置失败文本("敌人角色获取失败！");
					return;
				}
				掉落道具组.AddRange(敌人角色模型.掉落道具);
				掉落经验 += 方法.取随机数.Next(敌人角色模型.掉落经验[0], 敌人角色模型.掉落经验[1] + 1);
				角色组.Add(注册角色(敌人站位, (Marker2D)站位数组[敌人站位], 敌人角色模型.取综合属性(new C战斗属性())));
			}

			// 按照角色战斗属性速度排序 速度快点优先出手
			角色组.Sort((a, b) => b.角色模型.战斗属性.速度.CompareTo(a.角色模型.战斗属性.速度));

			int 回合数 = 0;
			回合数标签.Visible = true;
			地图名标签.Visible = true;

			await 开始战斗();

			async Task 开始战斗()
			{
				do
				{
					for (int i = 0; i < 角色组.Count; i++)
					{
						组件角色 攻击方 = 角色组[i];

						// 判断本回合攻击角色体力, 如果为零就跳过;
						if (攻击方.角色模型.战斗属性.体力 <= 0)
						{
							continue;
						}

						int 对手索引 = 取本轮对手(角色组, i);
						if (对手索引 == -1)
						{
							if (攻击方.角色模型.基础属性.战斗类型 != E角色战斗类型.敌人)
							{
								Godot.Collections.Array<int> 掉落道具 = [];
								Godot.Collections.Array<string> 日志道具 = [];

								// 随机掉落的道具
								for (int j = 0; j < 方法.取随机数.Next(敌人总数 - 1, 敌人总数 + 2); j++)
								{
									E道具索引 道具索引 = 掉落道具组[方法.取随机数.Next(0, 掉落道具组.Count)];
									日志道具.Add(道具索引.ToString());
									掉落道具.Add((int)道具索引);
								}

								// 随机掉落的装备
								for (int j = 0; j < 方法.取随机数.Next(配置.随机野外掉落装备概率[0], 配置.随机野外掉落装备概率[1]); j++)
								{
									E装备索引 装备索引 = 地图数据.装备[方法.取随机数.Next(0, 地图数据.装备.Count)];
									日志道具.Add(装备索引.ToString());
									掉落道具.Add((int)装备索引);
								}
								游戏管理.日志实例.置战斗胜利文本(Json.Stringify(日志道具), 掉落经验.ToString());
								游戏管理.玩家实例.置玩家职级经验(掉落经验);
								EmitSignal(SignalName.信号战斗结束, 掉落道具);
							}
							else
							{
								游戏管理.日志实例.置失败文本("很遗憾，战斗失败！");
							}
							await ToSignal(GetTree().CreateTimer(2 * 配置.战斗加速[游戏存档.战斗加速]), Timer.SignalName.Timeout);
							return;
						}

						if (i == 0)
						{
							回合数 += 1;
							回合数标签.Text = "第 " + 回合数 + " 回合";
							// 每回合延迟
							await ToSignal(GetTree().CreateTimer(0.8 * 配置.战斗加速[游戏存档.战斗加速]), Timer.SignalName.Timeout);
						}

						组件角色 防御方 = 角色组[对手索引];

						await 执行攻击操作(攻击方, 防御方);
					}
				} while (true);
			}
		} while (true);
	}

	private 组件角色 注册角色(int 角色站位, Marker2D 角色位置, C角色模型 角色模型)
	{
		组件角色 角色变量 = 角色场景.Instantiate<组件角色>();
		角色变量.Name = 角色模型.基础属性.名称;
		角色变量.Position = 角色位置.Position;
		角色变量.角色站位 = 角色站位;
		角色变量.角色模型 = 角色模型;
		角色放置层.AddChild(角色变量);
		return 角色变量;
	}

	private void 清空角色()
	{
		foreach (var 子项 in 角色放置层.GetChildren())
		{
			子项.QueueFree();
		}
	}

	// 按照体力绝对值最少的选择本轮对手 
	private int 取本轮对手(List<组件角色> 角色组, int 攻击角色索引)
	{
		int 对手索引 = -1;
		int 攻击方标识 = 角色组[攻击角色索引].角色模型.基础属性.战斗类型 == E角色战斗类型.敌人 ? 0 : 1;
		for (int i = 0; i < 角色组.Count; i++)
		{
			int 防御方标识 = 角色组[i].角色模型.基础属性.战斗类型 == E角色战斗类型.敌人 ? 0 : 1;
			if (i != 攻击角色索引 && 攻击方标识 != 防御方标识 && 角色组[i].角色模型.战斗属性.体力 > 0)
			{
				if (对手索引 == -1)
				{
					对手索引 = i;
				}
				else
				{
					if (角色组[i].角色模型.战斗属性.体力 < 角色组[对手索引].角色模型.战斗属性.体力)
					{
						对手索引 = i;
					}
				}
			}
		}
		return 对手索引;
	}

	private async Task 执行攻击操作(组件角色 攻击方, 组件角色 防御方)
	{
		var 攻击方战斗属性 = 攻击方.角色模型.战斗属性;
		var 防御方战斗属性 = 防御方.角色模型.战斗属性;

		// DeepSeek
		float 计算攻击伤害(out bool 暴击结果返回)
		{
			// 基础伤害计算 保底造成10%伤害
			float 伤害结果 = Math.Max(攻击方战斗属性.物伤 - 防御方战斗属性.防御, 攻击方战斗属性.物伤 * 0.1f);

			if (方法.取概率结果(攻击方战斗属性.命中率))
			{
				// 命中时增加命中值(受抵抗减免)
				伤害结果 += Math.Max(攻击方战斗属性.命中值 - 防御方战斗属性.抵抗, 0);

				// 命中后再判断暴击 可100%叠加暴击伤害
				bool 是否暴击 = 方法.取概率结果(攻击方战斗属性.暴击率);
				暴击结果返回 = 是否暴击;

				// 命中时增加暴击值(受韧性减免)
				if (是否暴击) { 伤害结果 += Math.Max(攻击方战斗属性.暴击值 - 防御方战斗属性.韧性, 0); }
			}
			else
			{
				// 未命中时仍有小概率触发暴击 暴击概率降低70%
				bool 未命中是否暴击 = 方法.取概率结果(攻击方战斗属性.暴击率 * 0.3f);
				暴击结果返回 = 未命中是否暴击;
				if (未命中是否暴击)
				{
					// 未命中暴击的伤害较低 暴击值降低30%
					if (未命中是否暴击) { 伤害结果 += Math.Max((攻击方战斗属性.暴击值 - 防御方战斗属性.韧性) * 0.7f, 0); }
				}
			}

			float 伤害随机系数 = 0.8f + 方法.取随机数.Next(1, 5) / 10;
			float 最终伤害 = 伤害结果 * 伤害随机系数;
			return Mathf.Max(最终伤害, 1);
		}

		float 攻击伤害 = 计算攻击伤害(out bool 是否暴击);

		攻击方.攻击();
		await ToSignal(攻击方, 组件角色.SignalName.信号动画结束);
		防御方.被攻击(攻击伤害, 是否暴击);
		await ToSignal(防御方, 组件角色.SignalName.信号动画结束);
		return;
	}
}
